package com.hmy.finance.common.oss;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CreateBucketRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class OssStsUtil {
    @Autowired
    private OssProperties ossProperties;


    /**
     * 获取临时授权访问
     * <p>
     * endpoint：STS接入地址，例如sts.cn-hangzhou.aliyuncs.com。各地域的STS接入地址请参见接入地址。
     * AccessKeyId、AccessKeySecret：访问密钥。
     * RoleArn：角色ARN。
     * RoleSessionName：用来标识临时访问凭证的名称，建议使用不同的应用程序用户来区分。
     * Policy：在扮演角色的时候额外添加的权限限制。请参见如何构建RAM Policy。 @See https://help.aliyun.com/document_detail/100680.html?spm=a2c4g.11186623.2.22.13e852a9QuGA3Z#concept-y5r-5rm-2gb
     */
    public AssumeRoleResponse.Credentials getCredentials() throws ClientException {
        String stsEndpoint = ossProperties.getStsEndpoint();
        String accessKeyId = ossProperties.getAccessKeyId();
        String accessKeySecret = ossProperties.getAccessKeySecret();
        String roleArn = ossProperties.getRoleArn();
        try {
            // 添加endpoint（直接使用STS endpoint，前两个参数留空，无需添加region ID）
            DefaultProfile.addEndpoint("", "", "Sts", stsEndpoint);

            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
            // 用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName("session-name");
            request.setPolicy(null);
            request.setDurationSeconds(3600L);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            AssumeRoleResponse.Credentials credentials = response.getCredentials();

            log.info("credentials:{}", credentials.getSecurityToken());
            return credentials;
        } catch (ClientException e) {
            log.info("文件上传出错,异常为:", e);
            throw e;
        }
    }


    /**
     * 从oss读取文件流
     *
     * @param ossFileUrl 文件路径
     * @return 文件流
     */
    public InputStream downloadFile(String ossFileUrl) {
        String endpoint = ossProperties.getEndpoint();
        String accessKeyId = ossProperties.getAccessKeyId();
        String accessKeySecret = ossProperties.getAccessKeySecret();
        String bucketName = ossProperties.getBucketName();

        OSSObject ossObject;
        InputStream inputStream = null;
        // 实时读取创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossObject = ossClient.getObject(bucketName, ossFileUrl);
        inputStream = ossObject.getObjectContent();
        return inputStream;
    }

    /**
     * 上传文件到oss 目录为MODULE_NAME/日期/
     *
     * @param in 文件流
     * @return oss路径
     */
    public String uploadByStream(InputStream in, String fileName) {
        String endpoint = ossProperties.getEndpoint();
        String accessKeyId = ossProperties.getAccessKeyId();
        String accessKeySecret = ossProperties.getAccessKeySecret();
        String bucketName = ossProperties.getBucketName();

        URL url = null;
        LocalDate date = LocalDate.now();
        //已日期"天"为目录
//        String path = "ossUtilObj.getModuleName()" + "/" + date.toString() + "/";
        String path = "finance" + "/" + date.toString() + "/";

        // 实时读取创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            if (!ossClient.doesBucketExist(bucketName)) {
                /*
                 * 创建新的 OSS bucket
                 */
                Bucket bucket = ossClient.createBucket(bucketName);
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                //设置公共读，供下载。
                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
                ossClient.createBucket(createBucketRequest);
            }

            //按天创建目录
            if (!ossClient.doesObjectExist(bucketName, path)) {
                ossClient.putObject(bucketName, path, new ByteArrayInputStream(new byte[0]));
            }

            // 上传Byte数组。
            ossClient.putObject(bucketName, path + fileName, in);
            ossClient.setObjectAcl(bucketName, path + fileName, CannedAccessControlList.PublicRead);

            Date expiration = new Date(System.currentTimeMillis() + 3600 * 24 & 365 * 10);//设置7天过期
            // 生成URL
            url = ossClient.generatePresignedUrl(bucketName, path + fileName, expiration);
            in.close();
        } catch (IOException e) {
            log.error("文件流close失败，result:{}", e);
        } catch (OSSException e) {
            log.error("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason.");
            log.error("Error Message: {}", e.getErrorMessage());
            log.error("Error Code:{} ", e.getErrorCode());
            log.error("Request ID: {}", e.getRequestId());
            log.error("Host ID: ", e.getHostId());
        } catch (com.aliyun.oss.ClientException e) {
            log.error("error Message: ", e.getMessage());
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        return Objects.nonNull(url) ? url.toString().split("\\?")[0] : null;
    }

}
